package cn.wanda.bi.sunshine.platform.server.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import cn.wanda.bi.sunshine.platform.server.client.request.elasticsearch.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.wanda.bi.sunshine.platform.server.aspect.AccessLabel;
import cn.wanda.bi.sunshine.platform.server.aspect.AuthLabelList;
import cn.wanda.bi.sunshine.platform.server.aspect.AuthLabelSingle;
import cn.wanda.bi.sunshine.platform.server.bean.mapper.UserLabelReturnFieldMapper;
import cn.wanda.bi.sunshine.platform.server.client.request.elasticsearch.BoolQuery;
import cn.wanda.bi.sunshine.platform.server.client.request.elasticsearch.ElasticSearchQuery;
import cn.wanda.bi.sunshine.platform.server.client.request.elasticsearch.QueryQuery;
import cn.wanda.bi.sunshine.platform.server.client.response.elasticsearch.UserLabelBean;
import cn.wanda.bi.sunshine.platform.server.client.wrapper.ElasticSearchClientWrapper;
import cn.wanda.bi.sunshine.platform.server.controller.request.DimUserLabelAllRequest;
import cn.wanda.bi.sunshine.platform.server.controller.request.DimUserLabelAllsRequest;
import cn.wanda.bi.sunshine.platform.server.controller.request.LabelQueryRequest;
import cn.wanda.bi.sunshine.platform.server.controller.response.common.ListResponse;
import cn.wanda.bi.sunshine.platform.server.controller.response.common.SimpleResponse;
import cn.wanda.bi.sunshine.platform.server.utils.JsonUtil;
import cn.wanda.bi.sunshine.platform.server.utils.PasswordUtil;

/**
 * Created by wangfupeng1
 */
@Service
public class LabelService {

	public static final Logger logger = LoggerFactory.getLogger(LabelService.class);

	@Autowired
	private ElasticSearchClientWrapper elasticSearchClientWrapper;

	@Autowired
	UserLabelReturnFieldMapper dimUserLabelAllReturnFieldMapper;

	@Autowired
	LabelDictionaryService labelDictionaryService;

	@Autowired
	private HttpServletRequest request;

	public ElasticSearchQuery getQuery(LabelQueryRequest request) {
		ElasticSearchQuery query = new ElasticSearchQuery();
		query.setQuery(getBoolQuery(request));
		query.setSort(getSort(request));
		return query;
	}

	public QueryQuery getBoolQuery(LabelQueryRequest labelQueryRequest) {
		BoolQuery bool = new BoolQuery();
		List<Map<String, Object>> musts = new ArrayList<Map<String, Object>>();
		List<Map<String, Object>> shoulds = new ArrayList<Map<String, Object>>();
		List<Map<String, Object>> mustNots = new ArrayList<Map<String, Object>>();
		if (labelQueryRequest.getRequests() == null) {
			Map<String, Object> must = new HashMap<String, Object>();
			must.put("match_all", new HashMap<String, String>());
			musts.add(must);
		} else {
			labelQueryRequest.getRequests().forEach(request -> {
				if (labelQueryRequest.getLogic() == 0) {
					if (request.getOperator() == 0) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("gt", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						musts.add(range);
					} else if (request.getOperator() == 1) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("lt", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						musts.add(range);
					} else if (request.getOperator() == 2) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("gte", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						musts.add(range);
					} else if (request.getOperator() == 3) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("lte", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						musts.add(range);
					} else if (request.getOperator() == 4) {
						Map<String, Object> must = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						mapValue.put(request.getLabel(), request.getValue());
						must.put("term", mapValue);
						musts.add(must);
					} else if (request.getOperator() == 5) {

						Map<String, Object> mustNot = new HashMap<String, Object>();
						Map<String, Object> mapNotValue = new HashMap<String, Object>();
						mapNotValue.put(request.getLabel(), request.getValue());
						mustNot.put("term", mapNotValue);
						mustNots.add(mustNot);
					} else if (request.getOperator() == 6) {
						if (request.getType() == 1) {
							List<String> values = JsonUtil.toList(request.getValue(), String.class);
							List<Map<String, Object>> should = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> shouldMap = new HashMap<String, Object>();
								Map<String, Object> shouldValue = new HashMap<String, Object>();
								shouldValue.put(request.getLabel(), value);
								shouldMap.put("term", shouldValue);
								should.add(shouldMap);
							});
							Map<String, Object> must = new HashMap<String, Object>();
							must.put("should", should);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", must);
							musts.add(boolMap);
						} else {
							List<Integer> values = JsonUtil.toList(request.getValue(), Integer.class);
							List<Map<String, Object>> should = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> shouldMap = new HashMap<String, Object>();
								Map<String, Object> shouldValue = new HashMap<String, Object>();
								shouldValue.put(request.getLabel(), value);
								shouldMap.put("term", shouldValue);
								should.add(shouldMap);
							});
							Map<String, Object> must = new HashMap<String, Object>();
							must.put("should", should);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", must);
							musts.add(boolMap);
						}
					} else if (request.getOperator() == 7) {
						if (request.getType() == 1) {
							List<String> values = JsonUtil.toList(request.getValue(), String.class);
							List<Map<String, Object>> must = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> mustMap = new HashMap<String, Object>();
								Map<String, Object> mustValue = new HashMap<String, Object>();
								mustValue.put(request.getLabel(), value);
								mustMap.put("term", mustValue);
								must.add(mustMap);
							});
							Map<String, Object> mustMap = new HashMap<String, Object>();
							mustMap.put("must_not", must);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", mustMap);
							musts.add(boolMap);
						} else {
							List<Integer> values = JsonUtil.toList(request.getValue(), Integer.class);
							List<Map<String, Object>> must = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> mustMap = new HashMap<String, Object>();
								Map<String, Object> mustValue = new HashMap<String, Object>();
								mustValue.put(request.getLabel(), value);
								mustMap.put("term", mustValue);
								must.add(mustMap);
							});
							Map<String, Object> mustMap = new HashMap<String, Object>();
							mustMap.put("must_not", must);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", mustMap);
							musts.add(boolMap);
						}
					}
				} else if (labelQueryRequest.getLogic() == 1) {
					if (request.getOperator() == 0) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("gt", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						shoulds.add(range);
					} else if (request.getOperator() == 1) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("lt", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						shoulds.add(range);
					} else if (request.getOperator() == 2) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("gte", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						shoulds.add(range);
					} else if (request.getOperator() == 3) {
						Map<String, Object> range = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						Map<String, Object> mayKey = new HashMap<String, Object>();
						mapValue.put("lte", request.getValue());
						mayKey.put(request.getLabel(), mapValue);
						range.put("range", mayKey);
						shoulds.add(range);
					} else if (request.getOperator() == 4) {
						Map<String, Object> should = new HashMap<String, Object>();
						Map<String, Object> mapValue = new HashMap<String, Object>();
						mapValue.put(request.getLabel(), request.getValue());
						should.put("term", mapValue);
						shoulds.add(should);
					} else if (request.getOperator() == 5) {

						Map<String, Object> mustNot = new HashMap<String, Object>();
						Map<String, Object> mapNotValue = new HashMap<String, Object>();
						Map<String, Object> mapNotMap = new HashMap<String, Object>();
						Map<String, Object> boolMap = new HashMap<String, Object>();
						mapNotValue.put(request.getLabel(), request.getValue());
						mustNot.put("term", mapNotValue);
						mapNotMap.put("must_not", mustNot);
						boolMap.put("bool", mapNotMap);
						shoulds.add(mustNot);
					} else if (request.getOperator() == 6) {
						if (request.getType() == 1) {
							List<String> values = JsonUtil.toList(request.getValue(), String.class);
							List<Map<String, Object>> should = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> shouldMap = new HashMap<String, Object>();
								Map<String, Object> shouldValue = new HashMap<String, Object>();
								shouldValue.put(request.getLabel(), value);
								shouldMap.put("term", shouldValue);
								should.add(shouldMap);
							});
							Map<String, Object> must = new HashMap<String, Object>();
							must.put("should", should);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", must);
							shoulds.add(boolMap);
						} else {
							List<Integer> values = JsonUtil.toList(request.getValue(), Integer.class);
							List<Map<String, Object>> should = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> shouldMap = new HashMap<String, Object>();
								Map<String, Object> shouldValue = new HashMap<String, Object>();
								shouldValue.put(request.getLabel(), value);
								shouldMap.put("term", shouldValue);
								should.add(shouldMap);
							});
							Map<String, Object> must = new HashMap<String, Object>();
							must.put("should", should);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", must);
							shoulds.add(boolMap);
						}
					} else if (request.getOperator() == 7) {
						if (request.getType() == 1) {
							List<String> values = JsonUtil.toList(request.getValue(), String.class);
							List<Map<String, Object>> must = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> mustMap = new HashMap<String, Object>();
								Map<String, Object> mustValue = new HashMap<String, Object>();
								mustValue.put(request.getLabel(), value);
								mustMap.put("term", mustValue);
								must.add(mustMap);
							});
							Map<String, Object> mustMap = new HashMap<String, Object>();
							mustMap.put("must_not", must);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", mustMap);
							shoulds.add(boolMap);
						} else {
							List<Integer> values = JsonUtil.toList(request.getValue(), Integer.class);
							List<Map<String, Object>> must = new ArrayList<Map<String, Object>>();
							values.forEach(value -> {
								Map<String, Object> mustMap = new HashMap<String, Object>();
								Map<String, Object> mustValue = new HashMap<String, Object>();
								mustValue.put(request.getLabel(), value);
								mustMap.put("term", mustValue);
								must.add(mustMap);
							});
							Map<String, Object> mustMap = new HashMap<String, Object>();
							mustMap.put("must_not", must);
							Map<String, Object> boolMap = new HashMap<String, Object>();
							boolMap.put("bool", mustMap);
							shoulds.add(boolMap);
						}
					} else {
						Map<String, Object> must = new HashMap<String, Object>();
						must.put("match_all", new HashMap<String, String>());
						musts.add(must);
					}
				}
			});
		}
		bool.setMust(musts);
		bool.setMust_not(mustNots);
		bool.setShould(shoulds);
		QueryQuery queryQuery = new QueryQuery();
		queryQuery.setBool(bool);
		return queryQuery;
	}


	public ArrayList<Map<String, Order>> getSort(LabelQueryRequest request) {
		if(request.getSortField() ==null || request.getSortField().trim()==""){
			request.setSortField("puid");
		}
		Map<String, Order> map = new HashMap<String, Order>();
		Order order = new Order();
		if(null==request.getSortOrder()) {
			order.setOrder("desc");
		} else if (request.getSortOrder() == 0) {
			order.setOrder("desc");
		} else if (request.getSortOrder() == 1) {
			order.setOrder("asc");
		} else {
			order.setOrder("desc");
		}
		map.put(request.getSortField(), order);
		ArrayList<Map<String, Order>> sort = new ArrayList<Map<String, Order>>();
		sort.add(map);
		return sort;
	}
	
	public ListResponse queryUserLabel(LabelQueryRequest request, Integer index, Integer limit) {
		ElasticSearchQuery query = getQuery(request);
		if (index == null)
			index = 1;
		if (limit == null)
			limit = 10;
		query.setFrom((index - 1) * limit);
		query.setSize(limit);
		String cacheKey = PasswordUtil.MD5LowerCase(JsonUtil.toJson(query));
		return elasticSearchClientWrapper.userLabelSearchListResponse(query, index, limit,cacheKey);
	}
	

	public SimpleResponse querySingle(LabelQueryRequest request) {
		ElasticSearchQuery query = getQuery(request);
		query.setFrom(0);
		query.setSize(2);
		String cacheKey = PasswordUtil.MD5LowerCase(JsonUtil.toJson(query));
		UserLabelBean userLabelBean = elasticSearchClientWrapper.userLabelBeanSearch(query,cacheKey);
		int totalCount = userLabelBean.getHits().getTotal();
		if (totalCount == 0) {
			return SimpleResponse.success();
		}
		return SimpleResponse.success(userLabelBean);
	}

	
	public Map<Object, Double> queryDimUserLabelPicture(List<DimUserLabelAllsRequest> dimUserLabelAllsRequests) {
		Map<Object, Double> maps = new HashMap<Object, Double>();
		if (dimUserLabelAllsRequests.size() == 1) {
			maps.put(dimUserLabelAllsRequests.get(0).getKey(), 1.00);
			return maps;
		}
		Long count = 0L;
		Map<String, Long> mapLong = new HashMap<String, Long>();
		mapLong.put("count", 0L);

		HashMap<Object, Integer> tempMap = new HashMap<>();
		dimUserLabelAllsRequests.forEach(request -> {
			ElasticSearchQuery query = getQuery(request.getRequest());
			String cacheKey = PasswordUtil.MD5LowerCase(JsonUtil.toJson(query));
			UserLabelBean userLabelBean = elasticSearchClientWrapper.userLabelBeanSearch(query,cacheKey);
			int TotalCount = userLabelBean.getHits().getTotal();
			tempMap.put(request.getKey(), TotalCount);
			mapLong.put("count", mapLong.get("count") + TotalCount);

		});
		count = mapLong.get("count");

		for (Map.Entry<Object, Integer> entry : tempMap.entrySet()) {
			double value = entry.getValue();
			if (count != 0) {
				double percent = value / count;
				maps.put(entry.getKey(), percent);
			} else {
				maps.put(entry.getKey(), 0.0);
			}

		}
		return maps;
	}

	public SimpleResponse queryBoolean(LabelQueryRequest request) {
		ElasticSearchQuery query = getQuery(request);
		String cacheKey = PasswordUtil.MD5LowerCase(JsonUtil.toJson(query));
		UserLabelBean userLabelBean = elasticSearchClientWrapper.userLabelBeanSearch(query,cacheKey);
		int totalCount = userLabelBean.getHits().getTotal();
		Map<String, Boolean> map = new HashMap<String, Boolean>();
		if (totalCount == 0) {
			map.put("isTrue", false);
			return SimpleResponse.success(map);
		}
		map.put("isTrue", true);
		return SimpleResponse.success(map);
	}

	public SimpleResponse countField(String field, LabelQueryRequest labelQueryRequest) {
		UserLabelBean userLabelBean = labelDictionaryService.QueryUserValue(field, labelQueryRequest);
		return SimpleResponse.success(userLabelBean);
	}

	public SimpleResponse countField1Field2(String field1, String field2, LabelQueryRequest labelQueryRequest) {
		UserLabelBean userLabelBean = labelDictionaryService.QueryUserValueField1Field2(field1, field2,
				labelQueryRequest);
		return SimpleResponse.success(userLabelBean);
	}

}
